﻿using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Channels;
using System.Threading.Tasks;
using Fleck;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using YB;
using YB_PrintPlug;
using static YB.WebSocket;
using static YB_Server_Windows.PopupWindow;

namespace YB_Server_Windows
{
    public static class Printlist
    {
        private static object lockObject = new object();
        private static string GenerateUniqueKey(int length)
        {
            const string chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
            StringBuilder keyBuilder = new StringBuilder();
            Random random = new Random();

            while (keyBuilder.Length < length)
            {
                char randomChar = chars[random.Next(chars.Length)];
                if (keyBuilder.ToString().IndexOf(randomChar) == -1)
                {
                    keyBuilder.Append(randomChar);
                }
            }

            return keyBuilder.ToString();
        }
        private class KindChannel
        {
            private string KindName = "";
            private string PrintName = "";
            private string _printId = "";
            private string _sendUid = "";
            private string _sendKind = "";
            private bool IsStop = false;
            private bool IsPause = false;
            private bool waitNext = false;
            private string waitId = "";
            private PopupWindow.PopWindow _popWindow { get; set; }
            public bool WaitNext
            {
                get
                {
                    return waitNext || IsPause;
                }
            }
            private static ManualResetEvent manualResetEvent = new ManualResetEvent(false);
            private static ManualResetEvent waitPlugReturn = new ManualResetEvent(false);
            private static ConcurrentDictionary<string, bool> _taskIdMap = new ConcurrentDictionary<string, bool>();

            private IWebSocketConnection Socket { get; set; }
            private Channel<KindSend> channel = Channel.CreateUnbounded<KindSend>();
            //发送当前打印状态给服务端
            private object state_lock = new object();
            private void SendPrintState(bool over)
            {
                //lock (state_lock)
                //{
                    if (_sendUid != "")//只有当前绑定了打印发送人的情况下才发送
                    {
                        Log.Write("设置打印进度条" + _popWindow.GetMax() + _popWindow.GetValue());
                        Dictionary<string, object> data = new Dictionary<string, object>();
                        data["sendUid"] = _sendUid;
                        data["sendKind"] = _sendKind;
                        data["printname"] = PrintName;
                        data["kindname"] = KindName;
                        data["maxvalue"] = _popWindow.GetMax();
                        data["printid"] = _printId;
                        data["value"] = _popWindow.GetValue();
                        if (over)
                        {
                            data["state"] = 1;
                        }
                        else
                        {
                            data["state"] = 0;
                        }

                        Dictionary<string, object> postData = new Dictionary<string, object>();
                        postData["data"] = JsonConvert.SerializeObject(data);
                        YbWeb.Post(User.GetHostUrl() + "/wmsapi/getinfo/", "setprintdata", postData);
                    }
                //}
            }
            public void SetSender(string uid, string uidkind)
            {
                _sendUid = uid;
                _sendKind = uidkind;
            }
            public int Count()
            {
                try
                {
                    return channel.Reader.Count;
                }
                catch
                {
                    return 0;
                }
            }
            public KindChannel(string kindname, string printname, KindSend data, IWebSocketConnection socket)
            {
                PrintName = printname;
                KindName = kindname;
                channel.Writer.WriteAsync(data);
                Socket = socket;
                _printId = Guid.NewGuid().ToString();
                _popWindow = PopupWindow.AddNewWindow(printname, "正在发送打印内容...", main.GetImageFromResources(PlugMap[kindname].icon));
                _popWindow.EnableProgressBar(0, data.OrderCount);
                _taskIdMap.TryAdd(data.Id, true);
            }
            public YB.errmsg AddSend(KindSend data)
            {
                try
                {
                    if (!_taskIdMap.ContainsKey(data.Id))
                    {
                        channel.Writer.WriteAsync(data);
                        _popWindow.AddMax(data.OrderCount);
                        _taskIdMap.TryAdd(data.Id, true);
                        SendPrintState(false);
                    }
                    else
                    {
                        return new errmsg(10221, "此订单重复");
                    }
                    return null;
                }
                catch (Exception ex)
                {
                    return new YB.errmsg(7004, "添加到打印通道错误[" + ex.ToString() + "]");
                }
            }
            private JObject GetJObject(string state)
            {
                JObject nowdata = new JObject();
                nowdata["printname"] = PrintName;
                nowdata["kind"] = KindName;
                nowdata["state"] = state;
                return nowdata;
            }
            public void Pause()
            {
                if (IsPause == false)
                {
                    IsPause = true;
                    manualResetEvent.WaitOne();
                }
            }
            public void RemoveMapKey(string key)
            {
                _taskIdMap.TryRemove(key, out _);
            }
            public void Continue()
            {
                if (waitNext)
                {
                    waitNext = false;
                    waitPlugReturn.Set();
                }
                if (IsPause)
                {
                    IsPause = false;
                    manualResetEvent.Set();
                }
            }
            public void Stop()
            {
                if (waitNext)
                {
                    if (waitId != "")
                    {
                        main.UpdatePrintListTask(PrintName, waitId, "已停止");
                    }
                    IsStop = true;
                    waitNext = false;
                    waitPlugReturn.Set();
                }
                if (IsPause)
                {
                    IsStop = true;
                    IsPause = false;
                    manualResetEvent.Set();
                }
            }
            public List<KindSend> GetData()
            {
                List<KindSend> outData = new List<KindSend>();
                ChannelReader<KindSend> reader = channel.Reader;
                while (reader.TryRead(out KindSend item))
                {
                    outData.Add(item);
                }
                return outData;
            }
            public void Clear()
            {
                while (channel.Reader.TryRead(out KindSend data))
                {
                    JObject sendjson = JObject.Parse(data.SendData);
                    string id = "";
                    YB.Config.ReadJObject<string>(sendjson, "requestID", ref id);
                    if (id == "")
                    {
                        YB.Config.ReadJObject<string>(sendjson, "key", ref id);
                    }
                    if (id != "")
                    {
                        main.UpdatePrintListTask(PrintName, id, "已取消");
                    }
                }
                if (IsPause)
                {
                    IsPause = false;
                    IsStop = true;
                    manualResetEvent.Set();
                }
            }
            public void Recover()
            {
                if (IsPause)
                {
                    IsPause = false;
                    manualResetEvent.Set();
                }
            }
            public void Run()
            {
                Task.Run(async () =>
                {
                    // 循环读取通道中的数据进行处理
                    while (await channel.Reader.WaitToReadAsync())
                    {
                        while (channel.Reader.TryRead(out KindSend data))
                        {
                            SendPrintState(false);
                            _popWindow.AddValue(data.OrderCount);
                            // 执行任务处理逻辑
                            YB.Log.Write ("$打印队列[" + PrintName + "]准备发送任务,ID[" + data.Id + "]任务类型" + data.Kind);
                            PrintPlug plug = GetMainPlug(data.Kind);
                            if (plug != null)
                            {
                                _popWindow.SetMsg("给打印组件[" + plug.Label + "]发送打印任务...");
                                _popWindow.SetIcon(plug.GetImage());
                                JObject sendjson = JObject.Parse(data.SendData);
                                string id = "";
                                YB.Config.ReadJObject<string>(sendjson, "requestID", ref id);
                                if (id == "")
                                {
                                    YB.Config.ReadJObject<string>(sendjson, "key", ref id);
                                }
                            Bgen:
                                if (IsStop)
                                {
                                    try
                                    {
                                        while (channel.Reader.TryRead(out _)) { }
                                    }
                                    catch (Exception e)
                                    {

                                    }

                                    goto End;
                                }
                                if (plug.LinkStatus)
                                {
                                    //YB.Log.Write("给" + plug.Label + "组件发送消息" + data.SendData);
                                    //YB.Log.Write("$打印队列[" + PrintName + "]使用打印组件[" + plug.Label + "]给打印机[" + PrintName + "]发送打印任务[" + id + "]");
                                    //AddPrintLog(PrintName, "$打印队列[" + PrintName + "]使用打印组件[" + plug.Label + "]给打印机[" + PrintName + "]发送打印任务[" + id + "]");
                                    plug.Send(PrintName, data.SendData, Socket);
                                    main.UpdatePrintListTask(PrintName, id, "已发送给组件");
                                    waitNext = true;
                                    waitId = id;
                                    RefreshPrintButton();
                                    waitPlugReturn.Reset();
                                    //YB.Log.Write("$打印队列[" + PrintName + "]暂停");
                                    waitPlugReturn.WaitOne();//这里必须等待打印机错误或者成功后才能继续
                                    //YB.Log.Write("$打印队列[" + PrintName + "]继续");
                                    RefreshPrintButton();
                                }
                                else
                                {
                                    SendMsg(Socket, 7007, "gotoplug", "打印组件[" + plug.Label + "]并没有在线，请检查后再发送", "error", GetJObject("Pause"));
                                    IsPause = true;
                                    manualResetEvent.Reset();
                                    RefreshPrintButton();
                                    manualResetEvent.WaitOne();
                                    RefreshPrintButton();
                                    goto Bgen;
                                }
                            }
                            else
                            {
                                //SendMsg(Socket, 7005, "gotoplug", "没有找到相应的打印组件[" + data.Kind + "]", "error");
                                //没有找到相应的组件就解析是否使用自己的打印
                            }
                        }
                    End:
                        IsStop = false;
                        //重置进度条
                        _popWindow.SetMax(0);
                        _popWindow.SetValue(0);
                        SendPrintState(true);
                        YB.Log.Write("$打印队列[" + PrintName + "]结束");
                        _popWindow.Close();
                    }
                });
            }
            void SendMsg(IWebSocketConnection socket, int code, string cmd, string msg, string state = "", JObject data = null)
            {
                try
                {
                    SocketReturn outdata = new SocketReturn();
                    outdata.Cmd = cmd;
                    outdata.Code = code;
                    outdata.State = state;
                    outdata.Status = state;
                    outdata.Msg = msg;
                    outdata.Data = data;
                    string returntext = outdata.ToString();
                    socket.Send(returntext);
                }
                catch (Exception ex)
                {
                    YB.Log.Write("发送信息给客户端错误[" + ex.ToString() + "]");
                }
            }
        }
        public class KindSend
        {
            public string Id = "";
            public string Kind = "";
            public string PlugName = "";
            public string SendData = "";
            public string CreateTime = "";
            public int OrderCount = 1;
            public KindSend(string kind, string senddata, int orderCount = 1)
            {
                Id = GenerateUniqueKey(16);
                Kind = kind;
                if (PlugMap.ContainsKey(kind))
                {
                    PlugName = PlugMap[kind].title;
                }
                else
                {
                    PlugName = "未知打印组件[" + kind + "]";
                }
                JObject sendData = JObject.Parse(senddata);
                if (sendData != null)
                {
                    string nowTaskId = "";
                    YB.Config.ReadJObject(sendData, "requestID", ref nowTaskId);
                    if (nowTaskId != "")
                    {
                        Id = nowTaskId;
                    }
                }
                int thisordercount = -1;
                YB.Config.ReadJObject(sendData, "orderCount", ref thisordercount);
                if (thisordercount > 0)
                {
                    orderCount = thisordercount;
                }
                CreateTime = DateTime.Now.ToString();
                SendData = senddata;
                OrderCount = orderCount;
            }
        }
        private class PlugKind
        {
            public string Kind = "";
            public string Port = "";
            public string WssPort = "";
            public string Address = "";
            public string title = "";
            public string icon = "";
        }
        public static YB.errmsg Init(string data)
        {
            try
            {
                PlugKind[] datalist = JsonConvert.DeserializeObject<PlugKind[]>(data);
                foreach (var item in datalist)
                {
                    if (item.Kind != "")
                    {
                        PlugMap[item.Kind] = item;
                    }
                }
            }
            catch (Exception ex)
            {
                return new YB.errmsg(7002, "初始化打印组件错误" + ex.ToString());
            }
            return null;
        }
        public static void AddPrintLog(string printname, string text)
        {
            YB.errmsg err = main.AddPrintLog(printname, text);
            if (err != null)
            {
                YB.Log.Write("添加打印日志错误[" + err.Error + "]");
            }
        }
        private static PrintPlug GetMainPlug(string name)
        {
            return main.GetPrintPlug(name);
        }
        private static ConcurrentDictionary<string, PlugKind> PlugMap = new ConcurrentDictionary<string, PlugKind>();
        private static ConcurrentDictionary<string, KindChannel> PlugKindMap = new ConcurrentDictionary<string, KindChannel>();
        private static Dictionary<string, int> PlugCountMap = new Dictionary<string, int>();
        public static List<KindSend> GetPrintList(string printname)
        {
            List<KindSend> outData = new List<KindSend>();
            if (PlugKindMap.ContainsKey(printname))
            {
                KindChannel usedata = PlugKindMap[printname];
                outData = usedata.GetData();
            }
            return outData;
        }
        public static YB.errmsg PausePtint(string printname)
        {
            if (PlugKindMap.ContainsKey(printname))
            {
                KindChannel usedata = PlugKindMap[printname];
                usedata.Pause();
                return null;
            }
            else
            {
                return new YB.errmsg(7010, "没有找到相关打印机");
            }
        }
        public static bool CheckWaitNext(string printname)
        {
            if (PlugKindMap.ContainsKey(printname))
            {
                KindChannel usedata = PlugKindMap[printname];
                return usedata.WaitNext;
            }
            else
            {
                return false;
            }
        }
        public static void ShowPrintCount(string printname, int count)
        {
            main.ShowPrintCount(printname, count);
        }
        public static void RefreshPrintButton()
        {
            main.RefreshPrintButton();
        }
        public static YB.errmsg ClearPrint(string printname)
        {
            if (PlugKindMap.ContainsKey(printname))
            {
                KindChannel usedata = PlugKindMap[printname];
                usedata.Clear();
                List<PrintPlug> plugs = main.GetPrintPlugs();
                foreach (PrintPlug item in plugs)
                {
                    item.Clear(printname);

                }
                if (PlugKindMap.ContainsKey(printname))
                {
                    PlugKindMap[printname].Clear();
                }
                YB.errmsg err = RecoverPrint(printname);
                return err;
            }
            else
            {
                return new YB.errmsg(7010, "没有找到相关打印机");
            }
        }
        public static YB.errmsg Continue(string printname)
        {
            List<PrintPlug> plugs = main.GetPrintPlugs();
            foreach (PrintPlug item in plugs)
            {
                item.Continue(printname);
            }
            var err = RecoverPrint(printname);
            return err;
        }
        public static YB.errmsg RecoverPrint(string printname,string taskid ="")
        {
            if (PlugKindMap.ContainsKey(printname))
            {
                KindChannel usedata = PlugKindMap[printname];
                //YB.Log.Write("$打印队列[" + printname + "]发送下一个任务,当前任务数量[" + usedata.Count().ToString() + "]");
                usedata.Continue();
                if (taskid != "" && taskid != null)
                {
                    usedata.RemoveMapKey(taskid);
                }
                return null;
            }
            else
            {
                return new YB.errmsg(7010, "没有找到相关打印机");
            }
        }
        public static YB.errmsg AddNewPrint(string printname, string kind, string uid, string uidkind, string printdata, IWebSocketConnection socket)
        {
            //lock (lockObject)
            //{
                if (!YB.PrintTask.CheckPrintName(printname))
                {
                    return new YB.errmsg(7001, "打印机名字不存在");
                }
                if (kind == "JX")
                {
                    JObject data = JObject.Parse(printdata);
                    string printName = YB.PrintTask.GetDefaultPrintName();
                    Config.ReadJObject<string>(data, "printname", ref printName);
                    printName = printname;
                    var datanode = data.SelectToken("order");
                    if (datanode is JArray)
                    {
                        foreach (var item in datanode.ToObject<JArray>())
                        {
                            JObject thisobj = item.ToObject<JObject>();
                            string templateurl = "";
                            Config.ReadJObject(thisobj, "TemplateUrl", ref templateurl);
                            string ids = "";
                            Config.ReadJObject<string>(thisobj, "requestID", ref ids);
                            if (templateurl != "")
                            {
                                var Template = YB.PrintTask.GetTemplateByUrl(templateurl);
                                if (Template != null)
                                {
                                    YB.PrintTask.AddNewPrintTask(printName, ids, Template, thisobj);
                                }
                            }
                            else
                            {
                                if (socket != null)
                                {
                                    SocketReturn outdataa = new SocketReturn();
                                    outdataa.Cmd = "printexp";
                                    outdataa.Code = 2002;
                                    outdataa.State = "Error";
                                    outdataa.Status = "Error";
                                    outdataa.Msg = "打印模板没有设置，无法打印";
                                    socket.Send(outdataa.ToString());
                                }
                            }
                        }
                    }
                    return null;
                }
                if (!PlugMap.ContainsKey(kind))
                {
                    return new YB.errmsg(7003, "打印组件类型不存在[" + kind + "]");
                }
                int index = 1;
                if (PlugCountMap.ContainsKey(printname))
                {
                    PlugCountMap[printname]++;
                    index = PlugCountMap[printname];
                }
                else
                {
                    PlugCountMap[printname] = index;
                }
                JObject sendData = JObject.Parse(printdata);
                int orderCount = 1;
                
                if (PlugKindMap.ContainsKey(printname))
                {
                    KindSend senddata = new KindSend(kind, printdata, orderCount);
                    //Console.WriteLine(kind);
                    YB.errmsg err = PlugKindMap[printname].AddSend(senddata);
                    if (err != null)
                    {
                        return err;
                    }
                    if (sendData != null)
                    {
                        string nowTaskId = "";
                        YB.Config.ReadJObject(sendData, "requestID", ref nowTaskId);
                        if (nowTaskId == "")
                        {
                            YB.Config.ReadJObject<string>(sendData, "key", ref nowTaskId);
                        }
                        YB.Config.ReadJObject<int>(sendData, "orderCount", ref orderCount);
                        if (nowTaskId != "")
                        {
                            PrintPlug plug = main.GetPrintPlug(kind);


                            main.AddTaskToList(index.ToString(), printname, plug.Label, nowTaskId, plug.GetImage(), orderCount);
                        }
                        else
                        {
                            YB.Log.Write("不可识别的打印任务[" + printdata + "]");
                            return new YB.errmsg(8002, "添加打印任务错误,无法读取任务Id");
                        }
                    }
                    return null;
                }
                else
                {
                    KindSend senddata = new KindSend(kind, printdata, orderCount);

                    Console.WriteLine(kind);
                    KindChannel nowkind = new KindChannel(kind, printname, senddata, socket);
                    if (uid != "")
                    {
                        nowkind.SetSender(uid, uidkind);
                    }
                    PlugKindMap.TryAdd(printname, nowkind);
                    nowkind.Run();
                    if (sendData != null)
                    {
                        string nowTaskId = "";
                        YB.Config.ReadJObject(sendData, "requestID", ref nowTaskId);
                        if (nowTaskId == "")
                        {
                            YB.Config.ReadJObject<string>(sendData, "key", ref nowTaskId);
                        }
                        YB.Config.ReadJObject<int>(sendData, "orderCount", ref orderCount);
                        if (nowTaskId != "")
                        {
                            PrintPlug plug = main.GetPrintPlug(kind);


                            main.AddTaskToList(index.ToString(), printname, plug.Label, nowTaskId, plug.GetImage(), orderCount);
                        }
                        else
                        {
                            YB.Log.Write("不可识别的打印任务[" + printdata + "]");
                            return new YB.errmsg(8002, "添加打印任务错误,无法读取任务Id");
                        }
                    }
                }
                return null;
            //}
        }
    }
}
